Experimental Software: Vivado 2021, Vitis 2021
Experimental Objective: Program the QSPI interface Flash via serial port
This experiment creates a new project in Vitis using two methods: Create Application Project and Create Platform Project
Open Vivado, after entering the Vivado interface, click "Create Project" in the "Quick Start" section. Then, in the popped-up Vivado project creation wizard interface, click "Next".
In the project naming interface. Set the project name to "Mind-Z7020_Vitis_Example", and choose the project path as needed. This time we place the project under the D:// folder. Note that the project name and path can only consist of English letters, numbers, and underscores, and cannot contain Chinese characters, spaces, or special characters. Check "Create project subdirectory", then click "Next":
Set the project type on this interface. Here we choose "RTL Project". This experiment does not require adding source files and constraint files, so check "Do not specify sources at this time". Checking this will omit the subsequent steps of adding source files and constraint files. Click "Next" to jump directly to the device selection interface.
Device selection interface. Select "Zynq-7000" in the Family column, select "-2" in the Speed column. It is important to note to select "clg400" in the Package column. Then, based on the ZYNQ chip model used on the core board, select "xc7z020clg400-2" from the device list below, as shown in the figure.
Display the summary information of the new project, as shown in the figure. Check the previously set project name, selected device model, and other information on this interface. If any project settings are found to be incorrect, you can return to the previous steps for modification using the Back button. After checking and confirming everything is correct, click "Finish" to complete the project creation.
The Vivado interface after project creation is completed is shown in the figure.
In the left navigation bar (Flow Navigator), click Create Block Design under IP Integrator. Then, in the popped-up dialog box, specify the name of the created Block Design, and enter "system" in the Design name field.
After clicking "OK", enter the graphical design interface. Click "+" in the Diagram window to add an IP core (Intellectual Property (IP) core, which are pre-designed, reusable hardware function modules provided by Xilinx (AMD) or third parties. These IP cores encapsulate specific hardware functions (such as processors, interface controllers, algorithm accelerators, etc.)). You can also use the shortcut Ctrl + I, or right-click on a blank area in the Diagram workspace, and then select "ADD IP".
After the IP catalog pops up, type "zynq" in the search bar, double-click "ZYNQ7 Processing System" to add this IP to the design.
After the addition is completed, the ZYNQ7 Processing System module appears in the Diagram, as shown below:
Next, configure the ZYNQ. Double-click the added ZYNQ7 Processing System module to enter the configuration interface of the ZYNQ7 processing system. Its left side is the page navigation, and the right side is the configuration information panel. As shown:
Zynq Block Design: Shows various configurable blocks of the Zynq processing system (PS), where the gray parts are unmodifiable, and the green highlighted parts are configurable. There are two ways to enter the configuration page: directly click on various configurable blocks (green highlighted parts) to enter their configuration page for configuration, or select the page navigation on the left to enter the corresponding page for configuration. PS-PL Configuration: Configure the PS-PL interface, including AXI GP, HP and other bus interfaces. Peripheral I/O Pins: Select MIO/EMIO for different I/O peripherals. MIO Configuration: Specifically configure MIO/EMIO for different I/O peripherals. Clock Configuration: Used to configure the PS input clock, peripheral clock, as well as DDR and CPU clocks, etc. DDR Configuration: Used to set DDR controller configuration information. SMC Timing Calculation: Used to perform SMC timing calculations. Interrupts: Used to configure PS-PL interrupt ports.
Configure the serial port used for printing information. Here, select the UART of the PS. Click the Peripheral I/O Pins page, and the following IO pin configuration interface appears. In the figure, set the Bank voltage according to the schematic (Bank0 is 3.3V, Bank1 is 1.8V).
The connection between the PS and external devices is mainly achieved through Multiplexed Input/Output (MIO). The 54 MIO pins of the PS can be used to connect to different peripheral interfaces. For example, MIO14 and MIO15 in the figure can be configured as pin interfaces for UART0, or as pin interfaces for I2C0 or CAN0. The specific configuration for which peripheral function depends on the development board.
MIO14 and MIO15 in BANK500 are used as pins for UART serial communication and are ultimately connected to the USB-to-serial chip CH340X on the baseboard. Therefore, to achieve serial communication functionality, we need to configure MIO14 and MIO15 as interface pins for the UART0 module in the PS.
Click the MIO Configuration page on the left, expand I/O Peripherals > UART0 on the right, and you can see its specific pin configuration information: MIO14 as the RX pin, MIO15 as the TX pin.
Configure the baud rate for UART0 serial communication. Under the General directory, you can see the default baud rate for UART0 is 115200. Other baud rates can be selected via the drop-down button.
Configure QSPI Flash: It can be configured in either Peripheral I/O Pins or MIO Configuration. If in the MIO Configuration page, you can select Memory Interfaces and then check Quad SPI Flash, at which point Single SS 4-bit IO will be automatically selected.
Configure the DDR3 controller of the PS. Click the DDR Configuration page on the left, and in the DDR Controller Configuration on the right, select the DDR device in the "Memory Part" column, choose MT41K256M16RE-125. The actual model on the core board is MT41K256M16TW-107. Because the provided options do not include the model MT41K256M16TW-107, this compatible model is selected. The core board uses two pieces of MT41K256M16TW-107, each with a data bus width of 16bit, so two pieces make 32bit. Keep other configuration options as default.
Configure the clock of the PS. Click the Clock Configuration page on the left. This interface is mainly used to configure the clock frequency in the ZYNQ PS. The PS on the core board uses a 33.3333MHz active crystal oscillator. For the CPU clock, DDR clock, and other peripheral clocks, keep the default settings.
This tutorial builds an embedded minimum system for ZYNQ7020, using only the PS side of ZYNQ. Therefore, we remove the interfaces for interaction between the PS and PL ends. On the Clock Configuration page, expand PL Fabric Clocks, and uncheck FCLK_CLK0/1/2/3.
Click the PS-PL Configuration page on the left, expand General on the right, and uncheck the corresponding items according to the figure below.
Configuration of ZYNQ7 Processing System is completed, click "OK". In the Diagram, you can see that the ZYNQ7 Processing System IP module only has DDR and FIXED_IO interfaces, as shown. Compared to when the IP was just added, the ZYNQ7 PS module has four fewer interfaces, corresponding to the several interfaces that were unchecked earlier.
Click the position indicated by the arrow in the figure above―Run Block Automation‖, and the following dialog box will pop up:
In this interface, we can choose to automatically connect the interfaces of the IP module. This project has only one IP module. Confirm to check processing_system7_0 on the left, then click "OK". At this point, the ZYNQ7 PS module has引出 two groups of external interfaces, namely DDR and FIXED_IO. The引出 interfaces will be assigned to specific pins of the ZYNQ device. By clicking the "+" at the interface of the ZYNQ7 PS module to expand these two groups of interfaces, you can observe which signals each contains.
After saving the current block design, you can verify if the current design has any errors. Click the button indicated by the arrow in the figure below. After the verification is completed, a dialog box pops up prompting no errors or critical warnings, click "OK", as shown below:
In the Sources window, select sysetm.bd under Design Sources, corresponding to the previous Block Design file. Right-click sysetm.bd, first click Reset Output Products, and then click "Generate Output Products":
The "Generate Output Products" dialog box pops up. You can keep the Synthesis Options default settings; Run Setings can be kept default or set to the maximum number of threads available for your personal computer's processor. Then click "Generate" to generate the synthesis, implementation, and simulation files for the design. During the "Generate" process, all required output results for the design will be generated. After Generate is completed, click "OK" in the popped-up dialog box.
Right-click system.bd again, then select "Create HDL Wrapper". In the popped-up dialog box, confirm to check "Let Vivado manage wrapper and auto-update", then click "OK". After creation is completed, the Design Sources structure is as shown below:
If PL resources are used in the design, pin constraints need to be added, and the design needs to be synthesized, implemented, and a Bitstream file generated. Since this project is a minimum system and does not use the PL part, these steps are not necessary, and the hardware can be directly exported to xsa.
Select File > Export > Export hardware from the menu bar.
In the popped-up interface, click next directly:
Since we have not generated a bitstream file, directly select the first option in the next interface. If a bitstream file has been generated, click the second option "Include bitstream", click next:
Next, a .xsa file will be generated. This file packages all hardware components and hardware platform information. The .xsa file will be used later with Vitis software or Linux.
Finally, click finish to complete:
After the hardware export is completed, select Tools > Launch vitis IDE from the menu bar. A pop-up will appear to select a namespace. You can create a new vitis folder under the entire project file.
In vitis, two types of projects can be created: platform project and application project.
platform project (Platform Project)
Based on the hardware description file (.xsa) exported from Vivado, create a platform containing the following: processor configuration (such as Zynq PS parameters, clocks, peripherals), programmable logic (PL) bitstream interface, memory mapping (DDR address space, peripheral registers).
Generate system-level support: Provide BSP (Board Support Package), driver libraries, and hardware abstraction layer for application calls.
One platform project can correspond to multiple application projects.
Generate .xpfm file (Xilinx Platform), which serves as a dependency for application projects.
Application project (Application Project)
Corresponds to the actual running application: Write software code running on the processor (such as ARM Cortex-A9) on an existing hardware platform (.xpfm or directly .xsa).
Based on the hardware platform of the platform project, no need to modify the underlying configuration. Supports bare metal (Baremetal), FreeRTOS, or Linux application development.
Generate executable file (.elf), which can be downloaded to DDR or programmed to Flash.
| Comparison Item | Platform Project | Application Project |
|---|---|---|
| Purpose | Define hardware infrastructure | Develop software running on hardware |
| Input Dependency | Vivado exported .xsa file | Existing platform (.xpfm or directly .xsa) |
| Modification Frequency | Low frequency (rarely changed after hardware is stable) | High frequency (code iterative development) |
| Output File | .xpfm (platform description file) | .elf (executable file) |
| Typical User | Hardware engineer/System architect | Software engineer/Embedded developer |
When creating a vitis project, you can first create a platform project, and then create an application project based on that platform project. You can also directly create an application project, but this will automatically create a platform project associated with that application project.
Here, taking creating the platform project first and then the application project as an example, let's talk about the creation process.
Subsequently, our application projects will be based on the created platform project.
Click "Browse", select the xsa file generated by vivado.
After selection, the operating system used will automatically pop up in the options below. Also check "Generate boot components", which will automatically add fsbl-related files to the hardware platform. Click "Finish":
At this point, the platform project creation is completed. Subsequent application projects we create will be based on this platform project. As shown:
If the hardware resource file (.xsa) is modified later (by recompiling in vivado to generate a new xsa file), just update the hardware resource file. The specific operation is to right-click on the platform project, select "update Hardware specification" from the popped-up options. In the popped-up window, select the newly generated xsa file. Then right-click on this platform project and select Build project to rebuild the platform project.
Next, we need to create an application project based on this platform project.
Create via File->New->Application Project:
In the popped-up interface, click next:
Select the previously created platform project:
Note here. If a platform project has not been created before, you can choose the Create a new platform from hardware tab. This will create the application project while also creating the platform project.
Fill in the project name, click next:
On the next page, you can choose the desired operating system. This time we use bare metal, click next:
Select "Hello World" in "Templates": Since a simple "Hello World" project is being created, there is already generated code in the template, which can be used without modification. Click "Finish":
At this point, the new application project is created, as shown:
Click "hello_world_system"->"hello_world"->src, inside is the software .c file:
Right-click "hello_world", click "build project" to compile the code. If there are no errors, an elf file will be generated. If there are errors, error prompts will be seen in the Problems page.
Configure the boot mode DIP switch of the development board to JTAG mode. Use a type-C USB cable to connect the JTAG port on the development board to the computer. The development board power is already on. Prepare another type-C USB cable to connect the PS_UART port on the development board to the computer. At the same time, open a serial port tool (such as MobaXterm) on the computer, select the corresponding recognized USB serial port, and set its baud rate to 115200.
Click "Xilinx"->"XSCT Console", the XSCT console will appear in the lower right corner. Enter the "connect" command. This command establishes a debugging connection with the target hardware (such as our Zynq-7020 development board). Then enter the "targets" command. This command lists all available debugging targets (processors/hardware components) in the current system. If the response shown in the figure appears, it means the connection is successfully established.
You can right-click and select Debug as:
Or operate via the Debug shortcut: Click the drop-down to pop up the drop-down options, and select the application project that needs debugging:
At this point, it will enter debug mode. By default, it jumps directly to main(). After that, you can perform step-by-step debugging, breakpoint debugging:
If you need to reload the program, you can right-click on Debug->[System Project Debug], select terminate and relaunch:
After Run, the "Hello World" and other character information will be printed on the computer's serial port tool.
There are two ways to generate BOOT.bin:
Right-click on "hello_world_system" and build project. This will automatically first compile "hello_world" to generate the elf file, then merge the generated elf file with the fsbl.elf file and bitstream file from the platform project to generate the BOOT.bin file. Ultimately, it is this BOOT.bin file that is programmed into the flash.
Right-click "hello_world_system", click "Create Boot Image". Or operate via the menu Xilinx->Create Boot Image.
Select "Create new BIF file", must ensure the "Output format" type is BIN, as shown below:
Add the following content in order:
fsbl.elf → type: bootloader
system.bit (if this file exists) → type: data, select the .bit file generated in vivado
hello_world.elf → type: data.
Finally, click "Create Image" to complete the creation.
If the result shown in the figure appears, it indicates successful creation.
When manually generating the BOOT.bin file later, you can click "Import form existing BIF file", select the correct file path, and click "Create Image ":
Click "Xilinx"->"Program Flash":
In the appeared interface, must ensure that the "Image File" is the generated BOOT.BIN file, the "Offset" starts from 0x00000000, and the "Init File" is the "fsbl.elf" file.
Explain the roles of the BOOT.Bin and fsbl.elf files:
BOOT.BIN:
Boot Image Package: Combines multiple files into a complete boot image for BootROM to read directly.
Contains Content (in order):
FSBL (fsbl.elf): Initializes hardware.
Bitstream file (system.bit, optional): Configures PL logic.
Application (hello_world.elf): User code.
Other components (such as U-Boot, PMUFW, etc., optional).
fsbl.elf:
Hardware Initialization:
Configures Zynq's PS (Processor System) clocks, DDR controller, peripherals (such as QSPI Flash, UART, etc.).
Loads the bitstream file (.bit) of the PL (Programmable Logic), configures FPGA logic.
Loading the Second Stage Program:
Reads the application (e.g., hello_world.elf) from Flash into DDR memory, and jumps to its entry address to execute.
Click "Program" and wait a few seconds. If "Flash Operation Successful" appears, it indicates successful programming of the QSPI Flash.
Power off the development board, set the DIP switch corresponding to the boot mode to QSPI boot mode. Connect the PS_UART serial port to the computer via a type-C cable, and power on. Open the corresponding serial port on the computer using a serial port tool. Then press the reset button on the development board, and you can see the corresponding output information on the computer's serial port tool.